package math;

import static math.ExpressionBuilder.or;

public class Or implements BooleanExpression {

  private BooleanExpression arg1;
  
  private BooleanExpression arg2;

  private Or(BooleanExpression arg1, BooleanExpression arg2) {
    this.arg1 = arg1;
    this.arg2 = arg2;
  }

  public BooleanExpression getArg1() {
    return arg1;
  }
  
  public BooleanExpression getArg2() {
    return arg2;
  }
  
  @Override
  public int countMembers() {
    return 1 + arg1.countMembers() + arg2.countMembers();
  }

  @Override
  public Expression simplify() {
    return this;
  }
  
  @Override
  public String toString() {
    return '(' + arg1.toString() + '|' + arg2.toString() + ")";
  }

  @Override
  public boolean matches(Expression expr) {
    if (expr instanceof Or) {
      Or eOr = (Or) expr;
      return arg1.matches(eOr.getArg1()) && arg2.matches(eOr.getArg2());
    } else
      return false;
  }

  @Override
  public boolean equals(Object obj) {
    if (obj instanceof Or) {
      Or or2 = (Or) obj;
      return or2.arg1.equals(arg1) && or2.arg2.equals(arg2);
    } else
      return false;
  }

  @Override
  public int hashCode() {
    return arg1.hashCode() ^ (arg2.hashCode() * 847823);
  }

  @Override
  public <R> R accept(ExpressionVisitor<R> visitor) {
    return visitor.visitOr(this);
  }

  public static BooleanExpression createOr(BooleanExpression arg1,
      BooleanExpression arg2) {
    return new Or(arg1, arg2);
  }

  @Override
  public BooleanExpression toDNF() {
    BooleanExpression newArg1 = arg1.toDNF();
    BooleanExpression newArg2 = arg2.toDNF();
    if (newArg1 == arg1 && newArg2 == arg2)
      return this;
    else
      return or(newArg1, newArg2);
  }
}
